<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    @import url("https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap");
svg {
  z-index: 100;
}

:root {
  --padding: 10vmin;
  --color-background: #D0CBC7;
  --font-size-large: 8vw;
  --font-size-medium: 4vw;
  --font-size-normal: 2vw;
}
@media only screen and (min-width: 800px) {
  :root {
    --font-size-large: 64px;
    --font-size-medium: 32px;
    --font-size-normal: 16px;
  }
}
@media only screen and (max-width: 500px) {
  :root {
    --font-size-large: 40px;
    --font-size-medium: 20px;
    --font-size-normal: 14px;
  }
}

a {
  color: white;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li {
  margin-top: 10px;
}

html, body {
  margin: 0;
  min-height: 100%;
  min-width: 100%;
  font-family: "Libre Baskerville", serif;
  background-color: var(--color-background);
  font-weight: 400;
  font-size: var(--font-size-normal);
  overflow-x: hidden;
}

canvas {
  position: fixed;
  z-index: 10;
  top: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
}

.solid {
  -webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
          clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}

.wireframe {
  -webkit-clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
          clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
}

.content {
  position: relative;
  z-index: 1;
}
.content .trigger {
  position: absolute;
  top: 0;
  height: 100%;
}
.content .section {
  position: relative;
  padding: var(--padding);
  --pad2: calc(var(--padding) * 2);
  width: calc(100vw - var(--pad2));
  height: calc(100vh - var(--pad2));
  margin: 0 auto;
  z-index: 2;
}
.content .section.dark {
  color: white;
  background-color: black;
}
.content .section.right {
  text-align: right;
}
.content .blueprint {
  position: relative;
  background-color: #131C2A;
  background-image: linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px), linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px;
  background-position: -2px -2px, -2px -2px, -1px -1px, -1px -1px;
  background-attachment: fixed;
}
.content .blueprint svg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  stroke: white;
  pointer-events: none;
  visibility: hidden;
}
.content .blueprint .dark {
  background-color: transparent;
}
.content .ground-container {
  position: relative;
  overflow: hidden;
}
.content .ground-container .parallax {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: -100px;
  background-repeat: no-repeat;
  background-position: top center;
  background-size: cover;
  transform-origin: top center;
}
.content .ground-container .ground {
  z-index: -1;
  background-image: url("https://assets.codepen.io/557388/background-reduced.jpg");
}
.content .ground-container .clouds {
  z-index: 2;
  background-image: url("https://assets.codepen.io/557388/clouds.png");
}
.content .scroll-cta, .content .credits {
  position: absolute;
  bottom: var(--padding);
}
.content .scroll-cta {
  font-size: var(--font-size-medium);
  opacity: 0;
}
.content .sunset {
  background: url("https://assets.codepen.io/557388/sunset-reduced.jpg") no-repeat top center;
  background-size: cover;
  transform-origin: top center;
}
.content h1, .content h2 {
  font-size: var(--font-size-large);
  margin: 0vmin 0 2vmin 0;
  font-weight: 700;
  display: inline;
}
.content h3 {
  font-size: var(--font-size-medium);
  font-weight: 400;
  margin: 0;
}
.content .end h2 {
  margin-bottom: 50vh;
}
.content .loading {
  position: fixed;
  width: 100vw;
  height: 100vh;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-medium);
}
</style>
<body>
    <div class="content">
        <div class="loading">Loading</div>
        <div class="trigger"></div>
        <div class="section">
            
            <h1>Airplanes.</h1>
            <h3>The beginners guide.</h3>
            <p>You've probably forgotten what these are.</p>
    <!-- 		<div class="phonetic">/ ˈɛərˌpleɪn /</div> -->
            <div class="scroll-cta">Scroll</div>
        </div>
        
        <div class="section right">
            <h2>They're kinda like buses...</h2>
        </div>
        
        <div class="ground-container">
            <div class="parallax ground"></div>
            <div class="section right">
                <h2>..except they leave the ground.</h2>
                <p>Saaay what!?.</p>
            </div>
    
            <div class="section">
                <h2>They fly through the sky.</h2>
                <p>For realsies!</p>
            </div>
            
            <div class="section right">
                <h2>Defying all known physical laws.</h2>
                <p>It's actual magic!</p>
            </div>
            <div class="parallax clouds"></div>
        </div>
        
        <div class="blueprint">
            <svg width="100%" height="100%" viewbox="0 0 100 100">
                <line id="line-length" x1="10" y1="80" x2="90" y2="80" stroke-width="0.5"></line>
                <path id="line-wingspan" d="M10 50, L40 35, M60 35 L90 50" stroke-width="0.5"></path>
                <circle id="circle-phalange" cx="60" cy="60" r="15" fill="transparent" stroke-width="0.5"></circle>
            </svg>
            <div class="section dark ">
                <h2>The facts and figures.</h2>
                <p>Lets get into the nitty gritty...</p>
            </div>
            <div class="section dark length">
                <h2>Length.</h2>
                <p>Long.</p>
            </div>
            <div class="section dark wingspan">
                <h2>Wing Span.</h2>
                <p>I dunno, longer than a cat probably.</p>
            </div>
            <div class="section dark phalange">
                <h2>Left Phalange</h2>
                <p>Missing</p>
            </div>
            <div class="section dark">
                <h2>Engines</h2>
                <p>Turbine funtime</p>
            </div>
    <!-- 		<div class="section"></div> -->
        </div>
        <div class="sunset">
            <div class="section"></div>
            <div class="section end">
                <h2>Fin.</h2>
                <ul class="credits">
                    <li>Plane model by <a href="https://poly.google.com/view/8ciDd9k8wha" target="_blank">Google</a></li>
                    <li>Animated using <a href="https://greensock.com/scrolltrigger/" target="_blank">GSAP ScrollTrigger</a></li>
                </ul>
            </div>
        </div>
    </div>
</body>
<script>
  function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;} // clearing the console (just a CodePen thing)

console.clear();

// there are 3 parts to this
//
// Scene:           Setups and manages threejs rendering
// loadModel:       Loads the 3d obj file
// setupAnimation:  Creates all the GSAP 
//                  animtions and scroll triggers 
//
// first we call loadModel, once complete we call
// setupAnimation which creates a new Scene

class Scene
{
  constructor(model)
  {_defineProperty(this, "render",



































































    () =>
    {
      for (var ii = 0; ii < this.views.length; ++ii) {if (window.CP.shouldStopExecution(3)) break;if (window.CP.shouldStopExecution(0)) break;

        var view = this.views[ii];
        var camera = view.camera;

        var bottom = Math.floor(this.h * view.bottom);
        var height = Math.floor(this.h * view.height);

        this.renderer.setViewport(0, 0, this.w, this.h);
        this.renderer.setScissor(0, bottom, this.w, height);
        this.renderer.setScissorTest(true);

        camera.aspect = this.w / this.h;
        this.renderer.render(this.scene, camera);
      }window.CP.exitedLoop(3);window.CP.exitedLoop(0);
    });_defineProperty(this, "onResize",

    () =>
    {
      this.w = window.innerWidth;
      this.h = window.innerHeight;

      for (var ii = 0; ii < this.views.length; ++ii) {if (window.CP.shouldStopExecution(4)) break;if (window.CP.shouldStopExecution(1)) break;
        var view = this.views[ii];
        var camera = view.camera;
        camera.aspect = this.w / this.h;
        let camZ = (screen.width - this.w * 1) / 3;
        camera.position.z = camZ < 180 ? 180 : camZ;
        camera.updateProjectionMatrix();
      }window.CP.exitedLoop(4);window.CP.exitedLoop(1);

      this.renderer.setSize(this.w, this.h);
      this.render();
    });this.views = [{ bottom: 0, height: 1 }, { bottom: 0, height: 0 }];this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });this.renderer.setSize(window.innerWidth, window.innerHeight);this.renderer.shadowMap.enabled = true;this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;this.renderer.setPixelRatio(window.devicePixelRatio);document.body.appendChild(this.renderer.domElement); // scene
    this.scene = new THREE.Scene();for (var _ii = 0; _ii < this.views.length; ++_ii) {if (window.CP.shouldStopExecution(2)) break;var _view = this.views[_ii];var _camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);_camera.position.fromArray([0, 0, 180]);_camera.layers.disableAll();_camera.layers.enable(_ii);_view.camera = _camera;_camera.lookAt(new THREE.Vector3(0, 5, 0));} //light
    window.CP.exitedLoop(2);this.light = new THREE.PointLight(0xffffff, 0.75);this.light.position.z = 150;this.light.position.x = 70;this.light.position.y = -20;this.scene.add(this.light);this.softLight = new THREE.AmbientLight(0xffffff, 1.5);this.scene.add(this.softLight); // group
    this.onResize();window.addEventListener('resize', this.onResize, false);var edges = new THREE.EdgesGeometry(model.children[0].geometry);let line = new THREE.LineSegments(edges);line.material.depthTest = false;line.material.opacity = 0.5;line.material.transparent = true;line.position.x = 0.5;line.position.z = -1;line.position.y = 0.2;this.modelGroup = new THREE.Group();model.layers.set(0);line.layers.set(1);this.modelGroup.add(model);this.modelGroup.add(line);this.scene.add(this.modelGroup);}}function loadModel()
{
  gsap.registerPlugin(ScrollTrigger);
  gsap.registerPlugin(DrawSVGPlugin);
  gsap.set('#line-length', { drawSVG: 0 });
  gsap.set('#line-wingspan', { drawSVG: 0 });
  gsap.set('#circle-phalange', { drawSVG: 0 });

  var object;

  function onModelLoaded() {
    object.traverse(function (child) {
      let mat = new THREE.MeshPhongMaterial({ color: 0x171511, specular: 0xD0CBC7, shininess: 5, flatShading: true });
      child.material = mat;
    });

    setupAnimation(object);
  }

  var manager = new THREE.LoadingManager(onModelLoaded);
  manager.onProgress = (item, loaded, total) => console.log(item, loaded, total);

  var loader = new THREE.OBJLoader(manager);
  loader.load('https://assets.codepen.io/557388/1405+Plane_1.obj', function (obj) {object = obj;});
}

function setupAnimation(model)
{
  let scene = new Scene(model);
  let plane = scene.modelGroup;

  gsap.fromTo('canvas', { x: "50%", autoAlpha: 0 }, { duration: 1, x: "0%", autoAlpha: 1 });
  gsap.to('.loading', { autoAlpha: 0 });
  gsap.to('.scroll-cta', { opacity: 1 });
  gsap.set('svg', { autoAlpha: 1 });

  let tau = Math.PI * 2;

  gsap.set(plane.rotation, { y: tau * -.25 });
  gsap.set(plane.position, { x: 80, y: -32, z: -60 });

  scene.render();

  var sectionDuration = 1;
  gsap.fromTo(scene.views[1],
  { height: 1, bottom: 0 },
  {
    height: 0, bottom: 1,
    ease: 'none',
    scrollTrigger: {
      trigger: ".blueprint",
      scrub: true,
      start: "bottom bottom",
      end: "bottom top" } });



  gsap.fromTo(scene.views[1],
  { height: 0, bottom: 0 },
  {
    height: 1, bottom: 0,
    ease: 'none',
    scrollTrigger: {
      trigger: ".blueprint",
      scrub: true,
      start: "top bottom",
      end: "top top" } });



  gsap.to('.ground', {
    y: "30%",
    scrollTrigger: {
      trigger: ".ground-container",
      scrub: true,
      start: "top bottom",
      end: "bottom top" } });



  gsap.from('.clouds', {
    y: "25%",
    scrollTrigger: {
      trigger: ".ground-container",
      scrub: true,
      start: "top bottom",
      end: "bottom top" } });



  gsap.to('#line-length', {
    drawSVG: 100,
    scrollTrigger: {
      trigger: ".length",
      scrub: true,
      start: "top bottom",
      end: "top top" } });



  gsap.to('#line-wingspan', {
    drawSVG: 100,
    scrollTrigger: {
      trigger: ".wingspan",
      scrub: true,
      start: "top 25%",
      end: "bottom 50%" } });



  gsap.to('#circle-phalange', {
    drawSVG: 100,
    scrollTrigger: {
      trigger: ".phalange",
      scrub: true,
      start: "top 50%",
      end: "bottom 100%" } });



  gsap.to('#line-length', {
    opacity: 0,
    drawSVG: 0,
    scrollTrigger: {
      trigger: ".length",
      scrub: true,
      start: "top top",
      end: "bottom top" } });



  gsap.to('#line-wingspan', {
    opacity: 0,
    drawSVG: 0,
    scrollTrigger: {
      trigger: ".wingspan",
      scrub: true,
      start: "top top",
      end: "bottom top" } });



  gsap.to('#circle-phalange', {
    opacity: 0,
    drawSVG: 0,
    scrollTrigger: {
      trigger: ".phalange",
      scrub: true,
      start: "top top",
      end: "bottom top" } });



  let tl = new gsap.timeline(
  {
    onUpdate: scene.render,
    scrollTrigger: {
      trigger: ".content",
      scrub: true,
      start: "top top",
      end: "bottom bottom" },

    defaults: { duration: sectionDuration, ease: 'power2.inOut' } });


  let delay = 0;

  tl.to('.scroll-cta', { duration: 0.25, opacity: 0 }, delay);
  tl.to(plane.position, { x: -10, ease: 'power1.in' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * .25, y: 0, z: -tau * 0.05, ease: 'power1.inOut' }, delay);
  tl.to(plane.position, { x: -40, y: 0, z: -60, ease: 'power1.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * .25, y: 0, z: tau * 0.05, ease: 'power3.inOut' }, delay);
  tl.to(plane.position, { x: 40, y: 0, z: -60, ease: 'power2.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * .2, y: 0, z: -tau * 0.1, ease: 'power3.inOut' }, delay);
  tl.to(plane.position, { x: -40, y: 0, z: -30, ease: 'power2.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: 0, z: 0, y: tau * .25 }, delay);
  tl.to(plane.position, { x: 0, y: -10, z: 50 }, delay);

  delay += sectionDuration;
  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * 0.25, y: tau * .5, z: 0, ease: 'power4.inOut' }, delay);
  tl.to(plane.position, { z: 30, ease: 'power4.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * 0.25, y: tau * .5, z: 0, ease: 'power4.inOut' }, delay);
  tl.to(plane.position, { z: 60, x: 30, ease: 'power4.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * 0.35, y: tau * .75, z: tau * 0.6, ease: 'power4.inOut' }, delay);
  tl.to(plane.position, { z: 100, x: 20, y: 0, ease: 'power4.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: tau * 0.15, y: tau * .85, z: -tau * 0, ease: 'power1.in' }, delay);
  tl.to(plane.position, { z: -150, x: 0, y: 0, ease: 'power1.inOut' }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { duration: sectionDuration, x: -tau * 0.05, y: tau, z: -tau * 0.1, ease: 'none' }, delay);
  tl.to(plane.position, { duration: sectionDuration, x: 0, y: 30, z: 320, ease: 'power1.in' }, delay);

  tl.to(scene.light.position, { duration: sectionDuration, x: 0, y: 0, z: 0 }, delay);
}

loadModel();
</script>
</html>